using Admin2025.Application.Common;
using Admin2025.Application.Dtos;
using Admin2025.Domain.Entities.App;
using Admin2025.Domain.Repositories;

namespace Admin2025.Application.Services;

public class UserAppServices : IUserAppServices
{
  private readonly IRepository<AppUser> _userRepo;
  private readonly IRepository<AppRole> _roleRepo;
  public UserAppServices(IRepository<AppUser> userRepo, IRepository<AppRole> roleRepo)
  {
    _userRepo = userRepo;
    _roleRepo = roleRepo;
  }

  // 暂时没有考试过滤、查找之类的功能,只考虑了分页，作业：请同时考试一下通用的过滤、查找功能，结合分页一起来
  public async Task<IEnumerable<UserDto>> GetAllAsync(PageRequestDto pageRequestDto)
  {
    var users = await _userRepo.GetPagedAsync(pageRequestDto.PageIndex, pageRequestDto.PageSize);
    return users.Select(u => new UserDto { Id = u.Id, Username = u.Username, Nickname = u.Nickname, AvatarUrl = u.AvatarUrl, IsEnabled = u.IsActived });
  }

  public async Task<UserDto> GetByIdAsync(Guid id)
  {
    var u = await _userRepo.GetByIdAsync(id) ?? throw new Exception("用户不存在");
    return new UserDto { Id = u.Id, Username = u.Username, Nickname = u.Nickname, AvatarUrl = u.AvatarUrl, IsEnabled = u.IsActived };
  }
  public async Task CreateAsync(CreateUserDto dto)
  {
    // 给密码加密
    var salt = Guid.NewGuid().ToString("N");
    var pwdHash = HashPassword(dto.Password, salt);

    var user = new AppUser { Username = dto.Username, Password = pwdHash, Salt = salt };
    await _userRepo.CreateAsync(user);
  }
  public async Task UpdateAsync(Guid id, UpdateUserDto dto)
  {
    var user = await _userRepo.GetByIdAsync(id) ?? throw new Exception("用户不存在");
    if (!string.IsNullOrEmpty(dto.Nickname))
    {
      user.UpdateNickname(dto.Nickname);
    }
    if (!string.IsNullOrEmpty(dto.AvatarUrl)) user.UpdateAvatar(dto.AvatarUrl);
    await _userRepo.UpdateAsync(user);
  }
  public async Task DeleteAsync(Guid id)
  {
    var user = await _userRepo.GetByIdAsync(id) ?? throw new Exception("用户不存在");
    await _userRepo.DeleteAsync(user);
  }

  public async Task EnableAsync(Guid id)
  {
    var user = await _userRepo.GetByIdAsync(id) ?? throw new Exception("用户不存在");
    user.Enable();
    await _userRepo.UpdateAsync(user);
  }
  public async Task<ApiResult> DisableAsync(Guid id)
  {
    var user = await _userRepo.GetByIdAsync(id);
    if (user == null)
    {
      return ApiResult.Fail(1004, "用户不存在或已经被删除");
    }
    user.Disable();
    await _userRepo.UpdateAsync(user);
    return ApiResult.Success(user);
  }
  public async Task AssignRoleAsync(Guid userId, Guid roleId)
  {
    var user = await _userRepo.GetByIdAsync(userId) ?? throw new Exception("用户不存在");
    var role = await _roleRepo.GetByIdAsync(roleId) ?? throw new Exception("角色不存在");
    user.AssignRole(role);
    await _userRepo.UpdateAsync(user);
  }

  public async Task RemoveRoleAsync(Guid userId, Guid roleId)
  {
    var user = await _userRepo.GetByIdAsync(userId) ?? throw new Exception("用户不存在");
    var role = await _roleRepo.GetByIdAsync(roleId) ?? throw new Exception("角色不存在");
    user.RemoveRole(role);
    await _userRepo.UpdateAsync(user);
  }

  public async Task UpdateAvatarAsync(Guid userId, string avatarUrl)
  {
    var user = await _userRepo.GetByIdAsync(userId) ?? throw new Exception("用户不存在");
    user.UpdateAvatar(avatarUrl);
    await _userRepo.UpdateAsync(user);
  }

  public async Task UpdateNicknameAsync(Guid userId, string nickname)
  {
    var user = await _userRepo.GetByIdAsync(userId) ?? throw new Exception("用户不存在");
    user.UpdateNickname(nickname);
    await _userRepo.UpdateAsync(user);
  }

  public async Task ChangePasswordAsync(Guid userId, string oldPwd, string newPwd)
  {
    var user = await _userRepo.GetByIdAsync(userId) ?? throw new Exception("用户不存在");
    var oldHash = HashPassword(oldPwd, user.Salt);
    var newHash = HashPassword(newPwd, user.Salt);
    user.ChangePassword(oldHash, newHash);
    await _userRepo.UpdateAsync(user);
  }



  // 加密密码
  private string HashPassword(string pwd, string salt)
  {
    using var sha256 = System.Security.Cryptography.SHA256.Create();
    var bytes = System.Text.Encoding.UTF8.GetBytes(pwd + salt);
    var hash = sha256.ComputeHash(bytes);
    return Convert.ToBase64String(hash);
  }
}